

<!DOCTYPE html>
<html lang="zh-CN" data-default-color-scheme=auto>



<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/img/favicon.png">
  <link rel="icon" href="/img/favicon.png">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="author" content="Cheney">
  <meta name="keywords" content="Coding">
  
    <meta name="description" content="利用MINIST数据集对构建的GAN网络进行训练，最终使得该网络能够脱离数据集自动生成以假乱真的手写体图像。">
<meta property="og:type" content="article">
<meta property="og:title" content="GAN手写体生成(MINIST)">
<meta property="og:url" content="https://cheney822.gitee.io/2021/10/04/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD__GAN%E6%89%8B%E5%86%99%E4%BD%93%E7%94%9F%E6%88%90(MINIST)/index.html">
<meta property="og:site_name" content="Cheney blog">
<meta property="og:description" content="利用MINIST数据集对构建的GAN网络进行训练，最终使得该网络能够脱离数据集自动生成以假乱真的手写体图像。">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://imgbed.cheney.cc/picgo/059312bf49564d7987bc925bb4385f8f-20220405210323434.png">
<meta property="og:image" content="https://imgbed.cheney.cc/picgo/4f5d1616ffa04d9a9959afac975b8fed-20220405210323482.png">
<meta property="og:image" content="https://imgbed.cheney.cc/picgo/698555f666ca4c0e83a727661b8716b8-20220405210323534.png">
<meta property="og:image" content="https://imgbed.cheney.cc/picgo/2b81803f50fe47269d8e08b0938bbfad-20220405210323578.png">
<meta property="og:image" content="https://imgbed.cheney.cc/picgo/37279616f8a64480a2b1df1d7aa95e9c-20220405210323645.png">
<meta property="og:image" content="https://imgbed.cheney.cc/picgo/c886b7155f8b4047b527b5718f33ed3b-20220405210323683.png">
<meta property="og:image" content="https://imgbed.cheney.cc/picgo/b30c0461443a44bfadb227b9c01d1090-20220405210323726.png">
<meta property="og:image" content="https://imgbed.cheney.cc/picgo/112e1d17900a4f3e93e4b948fd64c785.png">
<meta property="og:image" content="https://imgbed.cheney.cc/picgo/3925a831b2c545449e0661a3d2d9ebfa-20220405210323814.png">
<meta property="og:image" content="https://imgbed.cheney.cc/picgo/be17292be02a4e5bbbb9a3cad399b2bc-20220405210323858.png">
<meta property="article:published_time" content="2021-10-04T05:14:00.000Z">
<meta property="article:modified_time" content="2022-04-05T13:14:31.651Z">
<meta property="article:author" content="Cheney">
<meta property="article:tag" content="Python">
<meta property="article:tag" content="GAN">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="https://imgbed.cheney.cc/picgo/059312bf49564d7987bc925bb4385f8f-20220405210323434.png">
  
  
  <title>GAN手写体生成(MINIST) - Cheney blog</title>

  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4/dist/css/bootstrap.min.css" />


  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/github-markdown-css@4/github-markdown.min.css" />
  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/hint.css@2/hint.min.css" />

  
    
    
      
      <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/highlight.js@10/styles/github-gist.min.css" />
    
  

  
    <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3/dist/jquery.fancybox.min.css" />
  


<!-- 主题依赖的图标库，不要自行修改 -->

<link rel="stylesheet" href="//at.alicdn.com/t/font_1749284_ba1fz6golrf.css">



<link rel="stylesheet" href="//at.alicdn.com/t/font_1736178_lbnruvf0jn.css">


<link  rel="stylesheet" href="/css/main.css" />

<!-- 自定义样式保持在最底部 -->


  <script id="fluid-configs">
    var Fluid = window.Fluid || {};
    var CONFIG = {"hostname":"cheney822.gitee.io","root":"/","version":"1.8.14","typing":{"enable":true,"typeSpeed":70,"cursorChar":"_","loop":false},"anchorjs":{"enable":true,"element":"h1,h2,h3,h4,h5,h6","placement":"right","visible":"hover","icon":""},"progressbar":{"enable":true,"height_px":3,"color":"#29d","options":{"showSpinner":false,"trickleSpeed":100}},"copy_btn":true,"image_zoom":{"enable":true,"img_url_replace":["",""]},"toc":{"enable":true,"headingSelector":"h1,h2,h3,h4,h5,h6","collapseDepth":1},"lazyload":{"enable":true,"loading_img":"/img/loading.gif","onlypost":false,"offset_factor":2},"web_analytics":{"enable":false,"baidu":null,"google":null,"gtag":null,"tencent":{"sid":null,"cid":null},"woyaola":null,"cnzz":null,"leancloud":{"app_id":null,"app_key":null,"server_url":null,"path":"window.location.pathname","ignore_local":false}},"search_path":"/local-search.xml"};
  </script>
  <script  src="/js/utils.js" ></script>
  <script  src="/js/color-schema.js" ></script>
<meta name="generator" content="Hexo 5.4.1"></head>


<body>
  <header style="height: 70vh;">
    <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand" href="/">
      <strong>Cheney Blog</strong>
    </a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/">
                <i class="iconfont icon-home-fill"></i>
                首页
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/archives/">
                <i class="iconfont icon-archive-fill"></i>
                归档
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/categories/">
                <i class="iconfont icon-category-fill"></i>
                分类
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/tags/">
                <i class="iconfont icon-tags-fill"></i>
                标签
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/about/">
                <i class="iconfont icon-user-fill"></i>
                关于
              </a>
            </li>
          
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" target="_self" href="javascript:;" data-toggle="modal" data-target="#modalSearch" aria-label="Search">
              &nbsp;<i class="iconfont icon-search"></i>&nbsp;
            </a>
          </li>
        
        
          <li class="nav-item" id="color-toggle-btn">
            <a class="nav-link" target="_self" href="javascript:;" aria-label="Color Toggle">&nbsp;<i
                class="iconfont icon-dark" id="color-toggle-icon"></i>&nbsp;</a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

    <div class="banner" id="banner" parallax=true
         style="background: url('https://imgbed.cheney.cc/Blog_config/default.png') no-repeat center center;
           background-size: cover;">
      <div class="full-bg-img">
        <div class="mask flex-center" style="background-color: rgba(0, 0, 0, 0.3)">
          <div class="page-header text-center fade-in-up">
            <span class="h2" id="subtitle" title="GAN手写体生成(MINIST)">
              
            </span>

            
              <div class="mt-3">
  
  
    <span class="post-meta">
      <i class="iconfont icon-date-fill" aria-hidden="true"></i>
      <time datetime="2021-10-04 13:14" pubdate>
        2021年10月4日 下午
      </time>
    </span>
  
</div>

<div class="mt-1">
  
    <span class="post-meta mr-2">
      <i class="iconfont icon-chart"></i>
      9k 字
    </span>
  

  
    <span class="post-meta mr-2">
      <i class="iconfont icon-clock-fill"></i>
      
      
      46 分钟
    </span>
  

  
  
</div>

            
          </div>

          
        </div>
      </div>
    </div>
  </header>

  <main>
    
      

<div class="container-fluid nopadding-x">
  <div class="row nomargin-x">
    <div class="d-none d-lg-block col-lg-2"></div>
    <div class="col-lg-8 nopadding-x-md">
      <div class="container nopadding-x-md" id="board-ctn">
        <div class="py-5" id="board">
          <article class="post-content mx-auto">
            <!-- SEO header -->
            <h1 style="display: none">GAN手写体生成(MINIST)</h1>
            
            <div class="markdown-body">
              <blockquote>
<p>参考教材：人工智能导论(第4版) 王万良 高等教育出版社<br>实验环境：Python3.7 + Tensor flow  2.1</p>
</blockquote>
<p><kbd> ==人工智能导论实验导航== </kbd></p>
<p>==实验一：斑马问题== <a target="_blank" rel="noopener" href="https://blog.csdn.net/weixin_46291251/article/details/122246347">https://blog.csdn.net/weixin_46291251/article/details/122246347</a></p>
<p>==实验二：图像恢复== <a target="_blank" rel="noopener" href="https://blog.csdn.net/weixin_46291251/article/details/122561220">https://blog.csdn.net/weixin_46291251/article/details/122561220</a></p>
<p>==实验三：花卉识别== <a target="_blank" rel="noopener" href="https://blog.csdn.net/weixin_46291251/article/details/122561505">https://blog.csdn.net/weixin_46291251/article/details/122561505</a></p>
<p>==实验四：手写体生成== <a target="_blank" rel="noopener" href="https://blog.csdn.net/weixin_46291251/article/details/122576478">https://blog.csdn.net/weixin_46291251/article/details/122576478</a></p>
<p>==实验源码：== xxx</p>
<h1 id="4-1实验介绍"><a href="#4-1实验介绍" class="headerlink" title="4.1实验介绍"></a>4.1实验介绍</h1><h2 id="4-1-1实验背景"><a href="#4-1-1实验背景" class="headerlink" title="4.1.1实验背景"></a>4.1.1实验背景</h2><p>深度学习为人工智能核心技术，本章主要围绕深度学习涉及的全连接神经网络、卷积神经网络和对抗神经网络而开设的实验。</p>
<p>生成对抗网络是一种训练生成网络的框架，比如生成图片的深度卷积神经网络。构建一个用来生成图片的GAN模型需要同时具备判别模型和生成模型，判别模型，用来分析一张图片是真实的还是仿造的；生成模型使用反转的卷积层将输入转换为对应像素值的完整二维图像。本实验通过GAN模型的搭建，主要介绍TensorFlow2.0计算的基本流程，以及构建网络的基本要素。</p>
<h2 id="4-1-2实验目的"><a href="#4-1-2实验目的" class="headerlink" title="4.1.2实验目的"></a>4.1.2实验目的</h2><p>本章实验的主要目的是掌握深度学习相关基础知识点，了解深度学习相关基础知识，经典全连接神经网络、卷积神经网络和对抗神经网络。掌握不同神经网络架构的设计原理，熟悉使用Tensorflow 2.1深度学习框架实现深度学习实验的一般流程。同时对ModelArts自动学习模块、AI市场有初步认识，对Atlas200DK开发板模型部署相关内容有初步了解。</p>
<p>学习怎么定义和训练一个单独的判别模型，用来学习真假图片之间的不同点<br>学习怎么定义单独的生成模型，并训练同时具备生成和判别的复合模型<br>学习怎么评估GAN模型的表现，并使用最终得到的单独的生成模型生成图片</p>
<h2 id="4-1-3实验简介"><a href="#4-1-3实验简介" class="headerlink" title="4.1.3实验简介"></a>4.1.3实验简介</h2><p>利用MINIST数据集对构建的GAN网络进行训练，最终使得该网络能够脱离数据集自动生成以假乱真的手写体图像。<img src="https://imgbed.cheney.cc/picgo/059312bf49564d7987bc925bb4385f8f-20220405210323434.png" srcset="/img/loading.gif" lazyload alt="在这里插入图片描述"></p>
<h1 id="4-2概要设计"><a href="#4-2概要设计" class="headerlink" title="4.2概要设计"></a>4.2概要设计</h1><p>GAN主要包括了两个部分，即生成器generator与判别器discriminator。生成器主要用来学习真实图像分布从而让自身生成的图像更加真实，以骗过判别器。判别器则需要对接收的图片进行真假判别。在整个过程中，生成器努力地让生成的图像更加真实，而判别器则努力地去识别出图像的真假，这个过程相当于一个二人博弈，随着时间的推移，生成器和判别器在不断地进行对抗，最终两个网络达到了一个动态均衡：生成器生成的图像接近于真实图像分布，而判别器识别不出真假图像，对于给定图像的预测为真的概率基本接近0.5（相当于随机猜测类别）。所以：<br>对于给定的真实图片（real image），判别器要为其打上标签1；<br>对于给定的生成图片（fake image），判别器要为其打上标签0；<br>对于生成器传给辨别器的生成图片，生成器希望辨别器打上标签1。</p>
<h1 id="4-3详细设计"><a href="#4-3详细设计" class="headerlink" title="4.3详细设计"></a>4.3详细设计</h1><h2 id="4-3-1-实验数据准备"><a href="#4-3-1-实验数据准备" class="headerlink" title="4.3.1 实验数据准备"></a>4.3.1 实验数据准备</h2><p>数据集简介：<br>1). MNIST数据集来自美国国家标准与技术研究所（National Institute of Standards and<br> Technology ，简称NIST)；<br>2). 该数据集由来自250个不同人手写的数字构成，其中50%是高中学生，50%来自人口普查局<br>的工组人员；<br>3). 数据集可在<a target="_blank" rel="noopener" href="http://yann.lecun.com/exdb/mnist/">http://yann.lecun.com/exdb/mnist/</a>  获取, 它包含了四个部分:</p>
<ul>
<li>Training set images: train-images-idx3-ubyte.gz (9.9 MB, 解压后 47 MB, 包含 60,000 个样本)</li>
<li>Training set labels: train-labels-idx1-ubyte.gz (29 KB, 解压后 60 KB, 包含 60,000 个标签)</li>
<li>Test set images: t10k-images-idx3-ubyte.gz (1.6 MB, 解压后 7.8 MB, 包含 10,000 个样本)</li>
<li>Test set labels: t10k-labels-idx1-ubyte.gz (5KB, 解压后 10 KB, 包含 10,000 个标签)<br>4). mnist是一个入门级的计算机视觉数据集，它包含各种手写数字图片，下图展示了mnist中的一些图片：<img src="https://imgbed.cheney.cc/picgo/4f5d1616ffa04d9a9959afac975b8fed-20220405210323482.png" srcset="/img/loading.gif" lazyload alt="在这里插入图片描述"></li>
</ul>
<p>数据集加载：</p>
<figure class="highlight python"><table><tr><td class="gutter"><div class="code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></div></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np<br><span class="hljs-comment"># &#x27;&#x27;中为放置mnist.npz的相对路径，改为自己数据集存放的路径 </span><br>path = <span class="hljs-string">r&#x27;.\datasets\mnist.npz </span><br><span class="hljs-string">f = np.load(path)          #加载数据集</span><br><span class="hljs-string">trainX = f[&#x27;</span>x_train<span class="hljs-string">&#x27;]      #训练集数据获取</span><br><span class="hljs-string">trainy = f[&#x27;</span>y_train<span class="hljs-string">&#x27;]      #训练集数据标签获取</span><br><span class="hljs-string">testX = f[&#x27;</span>x_test<span class="hljs-string">&#x27;]       #测试集数据获取</span><br><span class="hljs-string">testy = f[&#x27;</span>y_test<span class="hljs-string">&#x27;]        #测试集数据标签获取</span><br><span class="hljs-string">print(&quot;Train&quot;, trainX.shape, trainy.shape)     #查看训练集数据形状及标签形状</span><br><span class="hljs-string">print(&quot;Test&quot;, testX.shape, testy.shape)        #查看验证集数据形状及标签形状</span><br></code></pre></td></tr></table></figure>

<p>输出结果：<br>Train (60000, 28, 28) (60000,)<br>Test (10000, 28, 28) (10000,)</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs python">可视化训练集前<span class="hljs-number">30</span>张图片:<br><span class="hljs-keyword">from</span> matplotlib <span class="hljs-keyword">import</span> pyplot   <span class="hljs-comment">#从matplotlib数据库导入pyplot模块</span><br><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">30</span>):              <span class="hljs-comment"># 使用range()函数产生0到29这30个数，建立for循环</span><br><span class="hljs-comment">#使用subplot()构建子图，第一个参数5表示每列有5张图，</span><br>第二个参数表示每行有<span class="hljs-number">6</span>张图，<span class="hljs-number">1</span>+i表示第(<span class="hljs-number">1</span>+i张图)<br>    pyplot.subplot(<span class="hljs-number">5</span>, <span class="hljs-number">6</span>, <span class="hljs-number">1</span> + i)    <br>    pyplot.axis(<span class="hljs-string">&#x27;off&#x27;</span>)          <span class="hljs-comment"># 关闭坐标轴(&quot;on&quot;为显示坐标轴)</span><br>     <span class="hljs-comment">#使用imshow()函数画出训练集相应图片原始像素数据，参数cmap = gray表示黑底白字图像，这边使用&quot;gray_r&quot;表示白底黑字图</span><br>pyplot.imshow(trainX[i], cmap=<span class="hljs-string">&#x27;gray_r&#x27;</span>)  <br>pyplot.show()                   <span class="hljs-comment"># 固定写法，展示图片</span><br></code></pre></td></tr></table></figure>

<p>输出结果：<br><img src="https://imgbed.cheney.cc/picgo/698555f666ca4c0e83a727661b8716b8-20220405210323534.png" srcset="/img/loading.gif" lazyload alt="在这里插入图片描述"></p>
<h2 id="4-3-2-GAN模型的框架"><a href="#4-3-2-GAN模型的框架" class="headerlink" title="4.3.2 GAN模型的框架"></a>4.3.2 GAN模型的框架</h2><p>伪代码如下：<img src="https://imgbed.cheney.cc/picgo/2b81803f50fe47269d8e08b0938bbfad-20220405210323578.png" srcset="/img/loading.gif" lazyload alt="在这里插入图片描述"></p>
<h2 id="4-3-3导入相关的包"><a href="#4-3-3导入相关的包" class="headerlink" title="4.3.3导入相关的包"></a>4.3.3导入相关的包</h2><h3 id="导入所需的包"><a href="#导入所需的包" class="headerlink" title="导入所需的包"></a>导入所需的包</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np<br><span class="hljs-keyword">from</span> numpy <span class="hljs-keyword">import</span> expand_dims     <span class="hljs-comment">#从numpy库导入expand_dims函数，用于数组增加维度</span><br><span class="hljs-keyword">from</span> numpy <span class="hljs-keyword">import</span> zeros           <span class="hljs-comment">#从numpy库导入zeros函数，用于生成元素都为0的数组</span><br><span class="hljs-keyword">from</span> numpy <span class="hljs-keyword">import</span> ones            <span class="hljs-comment">#从numpy库导入ones函数，用于生成元素都为1的数组</span><br><span class="hljs-keyword">from</span> numpy <span class="hljs-keyword">import</span> vstack          <span class="hljs-comment">#从numpy库导入vstack函数，用于在垂直方向(y轴)堆叠数组</span><br><span class="hljs-keyword">from</span> numpy.random <span class="hljs-keyword">import</span> randn    <span class="hljs-comment">#从numpy.random模块导入randn函数，numpy.random.randn(d0, d1, …, dn)是从标准正态分布中返回一个或多个样本值</span><br><span class="hljs-keyword">from</span> numpy.random <span class="hljs-keyword">import</span> randint  <span class="hljs-comment">#从numpy.random模块导入randint函数，用于生成整数，如np.random.randint(1, 5)是随机生成1，2，3，4这四个整数，注意前闭后开</span><br><span class="hljs-keyword">from</span> keras.datasets.mnist <span class="hljs-keyword">import</span> load_data  <span class="hljs-comment">#从keras.datasets.mnist加载load_data函数，此次实验我们直接从本地加载图片，故不使用这个函数</span><br><span class="hljs-keyword">from</span> tensorflow.keras.optimizers <span class="hljs-keyword">import</span> Adam            <span class="hljs-comment">#从keras.optimizers模块加载Adam优化器，用于训练模型</span><br><span class="hljs-keyword">from</span> tensorflow.keras.models <span class="hljs-keyword">import</span> Sequential          <span class="hljs-comment">#从keras.models库加载Sequentil序贯模型，用于线性堆叠多个网络层</span><br><span class="hljs-keyword">from</span> tensorflow.keras.layers <span class="hljs-keyword">import</span> Dense               <span class="hljs-comment">#从keras.layers库加载Dense层，用于全连接操作</span><br><span class="hljs-keyword">from</span> tensorflow.keras.layers <span class="hljs-keyword">import</span> Reshape             <span class="hljs-comment">#从keras.layers库加载reshape函数，用于将指定的矩阵变换成特定维数矩阵一种函数，且矩阵中元素个数不变，函数可以重新调整矩阵的行数、列数、维数。</span><br><span class="hljs-keyword">from</span> tensorflow.keras.layers <span class="hljs-keyword">import</span> Flatten             <span class="hljs-comment">#从keras.layers库加载Flaten函数，用来将输入“压平”，即把多维的输入一维化，常用在从卷积层到全连接层的过渡。Flaten不影响batch的大小</span><br><span class="hljs-keyword">from</span> tensorflow.keras.layers <span class="hljs-keyword">import</span> Conv2D              <span class="hljs-comment">#从keras.layers库加载Conv2D函数，用于卷积层操作</span><br><span class="hljs-keyword">from</span> tensorflow.keras.layers <span class="hljs-keyword">import</span> Conv2DTranspose     <span class="hljs-comment">#从keras.layers库加载Conv2DTranspore函数，此函数的操作可以看作Conv2D函数的逆操作</span><br><span class="hljs-keyword">from</span> tensorflow.keras.layers <span class="hljs-keyword">import</span> LeakyReLU           <span class="hljs-comment">#从keras.layers库加载LeakyReLU激活函数</span><br><span class="hljs-keyword">from</span> tensorflow.keras.layers <span class="hljs-keyword">import</span> Dropout             <span class="hljs-comment">#从keras.layers库加载Dropout函数</span><br><span class="hljs-keyword">from</span> matplotlib <span class="hljs-keyword">import</span> pyplot                <span class="hljs-comment">#从matplotlib库加载pyplot函数，用于显示图像</span><br></code></pre></td></tr></table></figure>

<h2 id="4-3-4-定义判别模型"><a href="#4-3-4-定义判别模型" class="headerlink" title="4.3.4 定义判别模型"></a>4.3.4 定义判别模型</h2><p>模型必须从我们的数据集中获取样本图像作为输入，并输出关于样本是真实还是假的分类预测。<br>这是一个二进制分类问题：输入：一个通道的图像，尺寸为28×28像素。 输出：二进制分类，样本是真实的（或假的）。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">define_discriminator</span>(<span class="hljs-params">in_shape=(<span class="hljs-params"><span class="hljs-number">28</span>,<span class="hljs-number">28</span>,<span class="hljs-number">1</span></span>)</span>):     <span class="hljs-comment">#定义判别模型，输入大小为(28,28,1)</span><br>    model = Sequential()                          <span class="hljs-comment">#构造序列模型Sequential()</span><br>    model.add(Conv2D(<span class="hljs-number">64</span>, (<span class="hljs-number">3</span>,<span class="hljs-number">3</span>), strides=(<span class="hljs-number">2</span>, <span class="hljs-number">2</span>), padding=<span class="hljs-string">&#x27;same&#x27;</span>, input_shape=in_shape)) <span class="hljs-comment"># 使用add()函数添加卷积层，Conv2D()添加卷积层，这里我们使用64个卷积核，卷积核大小3*3，步长为2，padding=&quot;same&quot;保持输出图像不变</span><br>    model.add(LeakyReLU(alpha=<span class="hljs-number">0.2</span>))           <span class="hljs-comment">#添加LeakyReLU()函数，在自变量小于0的部分，使用斜率0.2</span><br>    model.add(Dropout(<span class="hljs-number">0.4</span>))                   <span class="hljs-comment">#添加Dropout()函数，当前dropout比率为0.4，即如果某一层有1000个神经元，那经过dropout后，大约有400个值被置为0</span><br>    model.add(Conv2D(<span class="hljs-number">64</span>, (<span class="hljs-number">3</span>,<span class="hljs-number">3</span>), strides=(<span class="hljs-number">2</span>, <span class="hljs-number">2</span>), padding=<span class="hljs-string">&#x27;same&#x27;</span>))   <span class="hljs-comment">#添加第二层卷积层，同第一层</span><br>    model.add(LeakyReLU(alpha=<span class="hljs-number">0.2</span>))<br>    model.add(Dropout(<span class="hljs-number">0.4</span>))<br>    model.add(Flatten())                      <span class="hljs-comment">#添加Flaten层，将卷积层的多维数据一维化，卷积层到全连接层的过渡。</span><br>    model.add(Dense(<span class="hljs-number">1</span>, activation=<span class="hljs-string">&#x27;sigmoid&#x27;</span>)) <span class="hljs-comment">#添加Dense层，即全连接层，输出节点数为1，这里使用sidmoid()激活函数</span><br>    <span class="hljs-comment"># 编译模型</span><br>    opt = Adam(lr=<span class="hljs-number">0.0002</span>, beta_1=<span class="hljs-number">0.5</span>)         <span class="hljs-comment">#使用Adam激活函数，lr为学习率，值越大则表示权值调整动作越大，这里为0.0002；beta_1: (有偏)一阶矩估计的指数衰减因子,这里为0.5，用于动态调整每个参数的学习率</span><br>    model.<span class="hljs-built_in">compile</span>(loss=<span class="hljs-string">&#x27;binary_crossentropy&#x27;</span>, optimizer=opt, metrics=[<span class="hljs-string">&#x27;accuracy&#x27;</span>])  <span class="hljs-comment">#使用compile()函数定义损失函数，这里使用&#x27;binary_crossentropy&#x27;二元交叉熵损失函数；定义优化器及评价指标</span><br>    <span class="hljs-keyword">return</span> model<br></code></pre></td></tr></table></figure>

<h2 id="4-3-5定义生成模型"><a href="#4-3-5定义生成模型" class="headerlink" title="4.3.5定义生成模型"></a>4.3.5定义生成模型</h2><p>生成器模型负责创建手写数字的新的，假的但合理的图像。它通过从潜在空间中获取一个点作为输入并输出正方形灰度图像来实现此目的。<img src="https://imgbed.cheney.cc/picgo/37279616f8a64480a2b1df1d7aa95e9c-20220405210323645.png" srcset="/img/loading.gif" lazyload alt="在这里插入图片描述"></p>
<p>潜在空间是高斯分布值（例如100维）的任意定义的向量空间。它没有任何意义，但是通过在训练过程中从该空间中随机抽取点并将其提供给生成器模型，生成器模型将为潜点以及潜在空间分配含义，直到训练结束，潜矢量空间表示输出空间的MNIST图像的压缩表示，只有生成器才知道如何转换为看似可行的MNIST图像。<br>输入：潜在空间中的点，例如随机的一个服从高斯分布的100维向量。 输出：28×28像素的二维正方形灰度图像，像素值范围[0,1]。 注意：我们不必非要使用100元素向量作为输入；它是一个整数并且被广泛使用，但是我们也同样可以去尝试10、50或500维的空间。<br>开发生成器模型要求我们将向量从具有100个维度的潜在空间转换为具有28×28或784个值的2D数组。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">define_generator</span>(<span class="hljs-params">latent_dim</span>):<br>model = Sequential()<br><span class="hljs-comment">#定义网络所需节点数，输出图像的低分辨率图像大小7*7，</span><br><span class="hljs-number">128</span>可以理解为用这么多低分辨率图片代表输出图片<br>    n_nodes = <span class="hljs-number">128</span> * <span class="hljs-number">7</span> * <span class="hljs-number">7</span>                             <br>    model.add(Dense(n_nodes, input_dim=latent_dim))     <span class="hljs-comment">#添加潜在空间到节点的全连接层</span><br>model.add(LeakyReLU(alpha=<span class="hljs-number">0.2</span>))                     <br><span class="hljs-comment">#使用reshape()函数改变向量维度，使数据能像图像那样作为卷积层的输入</span><br>    model.add(Reshape((<span class="hljs-number">7</span>, <span class="hljs-number">7</span>, <span class="hljs-number">128</span>)))                     <br>    <span class="hljs-comment">#添加反卷积层，卷积核大小4*4，步长为2，使用padding使得最终结果为14*14的featuremap</span><br>    model.add(Conv2DTranspose(<span class="hljs-number">128</span>, (<span class="hljs-number">4</span>,<span class="hljs-number">4</span>), strides=(<span class="hljs-number">2</span>,<span class="hljs-number">2</span>), padding=<span class="hljs-string">&#x27;same&#x27;</span>)) <br>model.add(LeakyReLU(alpha=<span class="hljs-number">0.2</span>))<br><span class="hljs-comment">#同上一层反卷积层，将特征图从14*14转化为28*28                                    </span><br>    model.add(Conv2DTranspose(<span class="hljs-number">128</span>, (<span class="hljs-number">4</span>,<span class="hljs-number">4</span>), strides=(<span class="hljs-number">2</span>,<span class="hljs-number">2</span>), padding=<span class="hljs-string">&#x27;same&#x27;</span>)) <br>    model.add(LeakyReLU(alpha=<span class="hljs-number">0.2</span>))<br>    model.add(Conv2D(<span class="hljs-number">1</span>, (<span class="hljs-number">7</span>,<span class="hljs-number">7</span>), activation=<span class="hljs-string">&#x27;sigmoid&#x27;</span>, padding=<span class="hljs-string">&#x27;same&#x27;</span>))     <span class="hljs-comment">#使用普通卷积层最终得到一张特征图，使用sigmoid激活函数，使用&quot;same&quot;保持图片大小不变，28*28</span><br><span class="hljs-keyword">return</span> model<br></code></pre></td></tr></table></figure>


<h2 id="4-3-6-定义GAN网络"><a href="#4-3-6-定义GAN网络" class="headerlink" title="4.3.6 定义GAN网络"></a>4.3.6 定义GAN网络</h2><p>生成器模型中的权重将根据区分器模型的性能进行更新。当鉴别器善于检测假样本时，生成器会更新得更多；而当鉴别器模型相对较差或在检测假样本时会混淆时，生成器模型的更新会更少。这定义了这两个模型之间的零和或对抗关系。<br>我们采用一种较为简单的方法创建一个结合生成器模型和鉴别器模型的新模型。确切地说，我们不是在谈论或是创建新的第三个模型，而是一个新的逻辑模型（GAN模型），该模型使用独立生成器和鉴别器模型中已经定义的层和权重。<br>生成器模型仅与鉴别器在假示例中的表现有关。因此，当鉴别器中的所有层是GAN模型的一部分时，我们都将其标记为不可训练，这样就不会在伪造的示例上对它们进行更新和过度训练。<br>通过此逻辑GAN模型训练生成器时，还有一个更重要的变化。我们希望判别器认为生成器输出的样本是真实的，而不是假的。因此，当将生成器训练为GAN模型的一部分时，我们会将生成的样本标记为真实。<img src="https://imgbed.cheney.cc/picgo/c886b7155f8b4047b527b5718f33ed3b-20220405210323683.png" srcset="/img/loading.gif" lazyload alt="在这里插入图片描述"></p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">define_gan</span>(<span class="hljs-params">g_model, d_model</span>): <span class="hljs-comment"># 定义gan模型，使用g_model和d_model作为参数 </span><br>    d_model.trainable = <span class="hljs-literal">False</span>    <span class="hljs-comment"># 设置使判别模型的参数不发生改变</span><br>    model = Sequential()         <span class="hljs-comment">#定义 Sequential()模型</span><br>    model.add(g_model)           <span class="hljs-comment"># 添加生成器</span><br>    model.add(d_model)           <span class="hljs-comment"># 添加判别器</span><br>    opt = Adam(lr=<span class="hljs-number">0.0002</span>, beta_1=<span class="hljs-number">0.5</span>)   <span class="hljs-comment"># Adam优化器</span><br>    model.<span class="hljs-built_in">compile</span>(loss=<span class="hljs-string">&#x27;binary_crossentropy&#x27;</span>, optimizer=opt)  <span class="hljs-comment">#定义损失函数，优化器</span><br><span class="hljs-keyword">return</span> model<br></code></pre></td></tr></table></figure>

<h2 id="4-3-7-生成真实样本"><a href="#4-3-7-生成真实样本" class="headerlink" title="4.3.7 生成真实样本"></a>4.3.7 生成真实样本</h2><p>从MINIST数据集加载图片数据，并赋予标签</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-comment">#定义函数，dataset：数据集，n_samples:每个batch的样本数</span><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">generate_real_samples</span>(<span class="hljs-params">dataset, n_samples</span>): <br>    <span class="hljs-comment"># 使用randint()函数从[0,dataset.shape[0]]选择任意n_samples个整数作为索引</span><br>    ix = randint(<span class="hljs-number">0</span>, dataset.shape[<span class="hljs-number">0</span>], n_samples)  <br>X = dataset[ix]                              <span class="hljs-comment"># 根据索引从dataset中获取相应的图片</span><br><span class="hljs-comment"># 使用ones()函数生成n_samples个真实标签（一维向量），真实样本标签数值为1</span><br>    y = ones((n_samples, <span class="hljs-number">1</span>))    <br>    <span class="hljs-keyword">return</span> X, y<br></code></pre></td></tr></table></figure>

<p>从潜在空间生成点作为生成模型的输入</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-comment">#定义函数，参数latent_dim：潜在空间的维度；n_samples:生成的样本数</span><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">generate_latent_points</span>(<span class="hljs-params">latent_dim, n_samples</span>):  <br>    x_input = randn(latent_dim * n_samples)          <span class="hljs-comment">#在潜在空间生成样本点</span><br>    x_input = x_input.reshape(n_samples, latent_dim)  <span class="hljs-comment">#使用reshape()方法转化为网络的输入</span><br>    <span class="hljs-keyword">return</span> x_input<br></code></pre></td></tr></table></figure>

<p>使用生成模型生成虚假样本</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-comment">#参数g_model:生成模型； latent_dim:潜在空间维度； n_samples:样本数</span><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">generate_fake_samples</span>(<span class="hljs-params">g_model, latent_dim, n_samples</span>): <br>    x_input = generate_latent_points(latent_dim, n_samples)   <span class="hljs-comment"># 在潜在空间生成样本点</span><br>    X = g_model.predict(x_input)                          <span class="hljs-comment"># 将生成模型的预测结果作为生成的虚假样本</span><br>    y = zeros((n_samples, <span class="hljs-number">1</span>))                  <span class="hljs-comment"># 生成虚假样本的标签(一维向量)，虚假样本标签数值为0</span><br>    <span class="hljs-keyword">return</span> X, y<br></code></pre></td></tr></table></figure>

<p>保存生成的图片</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-comment">#参数examples：生成的样本；epoch:一个epoch就是将所有训练样本训练一次的过程；</span><br>n：子图列或宽的数量<br><span class="hljs-keyword">def</span> <span class="hljs-title function_">save_plot</span>(<span class="hljs-params">examples, epoch, n=<span class="hljs-number">10</span></span>):   <br>    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(n * n):<br>        pyplot.subplot(n, n, <span class="hljs-number">1</span> + i)   <span class="hljs-comment">#定义子图，子图每列n张图片，每行n张图片，当前为第(1+n)张图片  </span><br>        pyplot.axis(<span class="hljs-string">&#x27;off&#x27;</span>)           <span class="hljs-comment"># 关闭坐标</span><br>        <span class="hljs-comment"># 画出原始像素值,examples[i, :, :, 0]获取第i张图片的像素点</span><br>        pyplot.imshow(examples[i, :, :, <span class="hljs-number">0</span>], cmap=<span class="hljs-string">&#x27;gray_r&#x27;</span>)   <br>    filename = <span class="hljs-string">&#x27;generated_plot_e%03d.png&#x27;</span> % (epoch+<span class="hljs-number">1</span>)  <span class="hljs-comment"># 设置文件名，跟epoch相关</span><br>    pyplot.savefig(filename)                         <span class="hljs-comment"># 使用pyplot.savefig()函数将图像保存至文件夹</span><br>    pyplot.close()<br></code></pre></td></tr></table></figure>

<h2 id="4-3-8-训练模型"><a href="#4-3-8-训练模型" class="headerlink" title="4.3.8 训练模型"></a>4.3.8 训练模型</h2><p>在GAN模型中，生成器模型和判别器模型会被同时训练，在同一步训练过程中，分为两个过程，首先，我们会使用一半批次数量的真实样本+一般批次数量的生成样本(由生成模型生成，标签为0)训练判别模型；然后会生成一个批次的生成模型(由生成模型生成，标签为1)训练GAN模型。<br>GAN的训练分为如下几个步骤：</p>
<ul>
<li>1、随机选取batch_size个真实的图片。</li>
<li>2、随机生成batch_size个N维向量，传入到Generator中生成batch_size个虚假图片。</li>
<li>3、将真实图片和虚假图片当作训练集传入到Discriminator中进行训练（真实图片的label为1，虚假图片的label为0）。</li>
<li>4、将虚假图片的Discriminator预测结果与1的对比作为loss对Generator进行训练（与1对比的意思是，如果Discriminator将虚假图片判断为1，说明这个生成的图片很“真实”）。</li>
</ul>
<p>实验中：总的样本集训练过程n_epochs=100，每个step参与训练的样本数n_batch=256。每隔10个epoch评估判别模型表现，保存生成的图片及相应的生成模型</p>
<h1 id="4-4运行测试"><a href="#4-4运行测试" class="headerlink" title="4.4运行测试"></a>4.4运行测试</h1><h3 id="第一次迭代后"><a href="#第一次迭代后" class="headerlink" title="第一次迭代后"></a>第一次迭代后</h3><p><img src="https://imgbed.cheney.cc/picgo/b30c0461443a44bfadb227b9c01d1090-20220405210323726.png" srcset="/img/loading.gif" lazyload alt="在这里插入图片描述"></p>
<h3 id="第三次迭代后"><a href="#第三次迭代后" class="headerlink" title="第三次迭代后"></a>第三次迭代后</h3><p><img src="https://imgbed.cheney.cc/picgo/112e1d17900a4f3e93e4b948fd64c785.png" srcset="/img/loading.gif" lazyload alt="在这里插入图片描述"></p>
<h3 id="第六次迭代后"><a href="#第六次迭代后" class="headerlink" title="第六次迭代后"></a>第六次迭代后</h3><p><img src="https://imgbed.cheney.cc/picgo/3925a831b2c545449e0661a3d2d9ebfa-20220405210323814.png" srcset="/img/loading.gif" lazyload alt="在这里插入图片描述"></p>
<h3 id="最终第十次迭代后"><a href="#最终第十次迭代后" class="headerlink" title="最终第十次迭代后"></a>最终第十次迭代后</h3><p><img src="https://imgbed.cheney.cc/picgo/be17292be02a4e5bbbb9a3cad399b2bc-20220405210323858.png" srcset="/img/loading.gif" lazyload alt="在这里插入图片描述"></p>
<p>从以上生成的手写图片可知，随着训练的不断迭代，生成的效果也越来越好。</p>

            </div>
            <hr>
            <div>
              <div class="post-metas mb-3">
                
                  <div class="post-meta mr-3">
                    <i class="iconfont icon-category"></i>
                    
                      <a class="hover-with-bg" href="/categories/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/">人工智能</a>
                    
                  </div>
                
                
                  <div class="post-meta">
                    <i class="iconfont icon-tags"></i>
                    
                      <a class="hover-with-bg" href="/tags/Python/">Python</a>
                    
                      <a class="hover-with-bg" href="/tags/GAN/">GAN</a>
                    
                  </div>
                
              </div>
              
                <p class="note note-warning">
                  
                    本博客所有文章除特别声明外，均采用 <a target="_blank" href="https://creativecommons.org/licenses/by-sa/4.0/deed.zh" rel="nofollow noopener noopener">CC BY-SA 4.0 协议</a> ，转载请注明出处！
                  
                </p>
              
              
                <div class="post-prevnext">
                  <article class="post-prev col-6">
                    
                    
                      <a href="/2022/03/03/Caesar%E5%AF%86%E7%A0%81%E7%9A%84%E7%94%9F%E6%88%90%E4%B8%8E%E7%A0%B4%E8%A7%A3/">
                        <i class="iconfont icon-arrowleft"></i>
                        <span class="hidden-mobile">Caesar密码的生成与破解</span>
                        <span class="visible-mobile">上一篇</span>
                      </a>
                    
                  </article>
                  <article class="post-next col-6">
                    
                    
                      <a href="/2021/10/03/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD__%E5%9B%BE%E5%83%8F%E6%81%A2%E5%A4%8D(%E5%8A%A0%E5%99%AA%E4%B8%8E%E5%8E%BB%E5%99%AA)/">
                        <span class="hidden-mobile">图像恢复(加噪与去噪)</span>
                        <span class="visible-mobile">下一篇</span>
                        <i class="iconfont icon-arrowright"></i>
                      </a>
                    
                  </article>
                </div>
              
            </div>

            
          </article>
        </div>
      </div>
    </div>
    
      <div class="d-none d-lg-block col-lg-2 toc-container" id="toc-ctn">
        <div id="toc">
  <p class="toc-header"><i class="iconfont icon-list"></i>&nbsp;目录</p>
  <div class="toc-body" id="toc-body"></div>
</div>

      </div>
    
  </div>
</div>

<!-- Custom -->


    

    
      <a id="scroll-top-button" aria-label="TOP" href="#" role="button">
        <i class="iconfont icon-arrowup" aria-hidden="true"></i>
      </a>
    

    
      <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">搜索</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v"
                 for="local-search-input">关键词</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>
    

    
  </main>

  <footer class="text-center mt-5 py-3">
  <div class="footer-content">
     <a href="https://hexo.io" target="_blank" rel="nofollow noopener"><span>Hexo</span></a> <i class="iconfont icon-love"></i> <a href="https://cheney822.gitee.io/" target="_blank" rel="nofollow noopener"><span>备用网址</span></a> 
  </div>
  

  
  <!-- 备案信息 -->
  <div class="beian">
    <span>
      <a href="http://beian.miit.gov.cn/" target="_blank" rel="nofollow noopener">
        皖ICP备2022002876号-1
      </a>
    </span>
    
  </div>


  
</footer>


  <!-- SCRIPTS -->
  
  <script  src="https://cdn.jsdelivr.net/npm/nprogress@0/nprogress.min.js" ></script>
  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/nprogress@0/nprogress.min.css" />

  <script>
    NProgress.configure({"showSpinner":false,"trickleSpeed":100})
    NProgress.start()
    window.addEventListener('load', function() {
      NProgress.done();
    })
  </script>


<script  src="https://cdn.jsdelivr.net/npm/jquery@3/dist/jquery.min.js" ></script>
<script  src="https://cdn.jsdelivr.net/npm/bootstrap@4/dist/js/bootstrap.min.js" ></script>
<script  src="/js/events.js" ></script>
<script  src="/js/plugins.js" ></script>

<!-- Plugins -->


  <script  src="/js/local-search.js" ></script>



  
    <script  src="/js/img-lazyload.js" ></script>
  



  



  
    <script  src="https://cdn.jsdelivr.net/npm/tocbot@4/dist/tocbot.min.js" ></script>
  
  
    <script  src="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3/dist/jquery.fancybox.min.js" ></script>
  
  
    <script  src="https://cdn.jsdelivr.net/npm/anchor-js@4/anchor.min.js" ></script>
  
  
    <script defer src="https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js" ></script>
  






  <script  src="https://cdn.jsdelivr.net/npm/typed.js@2/lib/typed.min.js" ></script>
  <script>
    (function (window, document) {
      var typing = Fluid.plugins.typing;
      var title = document.getElementById('subtitle').title;
      
        typing(title);
      
    })(window, document);
  </script>















<!-- 主题的启动项 保持在最底部 -->
<script  src="/js/boot.js" ></script>


</body>
</html>
